//
// Created by Administrator on 2020/11/11.
//

#include "../include/l3IntfApi.h"

S_UeL2L3IntfContext *gpUeL2L3IntfContext = NULL;

int32_t UE_L2_L3I_Init(void)
{
    int32_t rc;

    gpUeL2L3IntfContext = OS_MemCalloc(1, sizeof(S_UeL2L3IntfContext));
    IF_RETURN(==, NULL, gpUeL2L3IntfContext, O5G_RC_ER, "UE_L2_L3I_Init() OS_MemCalloc() error!\n");

    rc = OS_UdpInit(&gpUeL2L3IntfContext->l3SockFd);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "UE_L2_L3I_Init() OS_UdpInit(l3SockFd) error!\n");

    rc = OS_UdpBind(gpUeL2L3IntfContext->l3SockFd, "127.0.0.1", UE_L3_2_L2_UDP_PORT);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "RAN_L2_L3I_Init() OS_UdpBind(l3SockFd) error!\n");

    rc = OS_UdpConnect(gpUeL2L3IntfContext->l3SockFd, "127.0.0.1", UE_L2_2_L3_UDP_PORT);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "RAN_L2_L3I_Init() OS_UdpConnect(l3SockFd) error!\n");

    rc = OS_SelectInit(&gpUeL2L3IntfContext->selector, NULL);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "UE_L2_L3I_Init() OS_SelectInit() error!\n");

    gpUeL2L3IntfContext->poller = POLLER_Create(POLL_FD_NUM_MAX);
    IF_RETURN(==, NULL, gpUeL2L3IntfContext->poller, O5G_RC_ER, "UE_L2_L3I_Init() POLLER_Create() error!\n");

    return O5G_RC_OK;
}

int32_t UE_L2_L3I_Final(void)
{
    int32_t rc;

    rc = OS_UdpFinal(gpUeL2L3IntfContext->l3SockFd);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "UE_L2_L3I_Final() OS_UdpFinal(l3SockFd) error!\n");

    rc = OS_SelectFinal(&gpUeL2L3IntfContext->selector);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "UE_L2_L3I_Final() OS_SelectFinal() error!\n");

    POLLER_Destroy(gpUeL2L3IntfContext->poller);

    OS_MemFree(gpUeL2L3IntfContext);

    return O5G_RC_OK;
}

void UE_L2_L3I_ProcL1ApiRspMsg()
{
    uint32_t size;
    S_UeCommMsgHdr *pCommMsgHdr;

    while (1)
    {
        pCommMsgHdr = VarRB_ReadRequest(gpUeL2Context->pL1iL3iMsgQue, &size);
        IF_BREAK(==, NULL, pCommMsgHdr, NO_LOG_MESSAGE);

        send(gpUeL2L3IntfContext->l3SockFd, pCommMsgHdr, pCommMsgHdr->size, MSG_DONTWAIT);
        VarRB_ReadConsume(gpUeL2Context->pL1iL3iMsgQue, pCommMsgHdr);
    }
}

void UE_L2_L3I_IndProcess(int32_t event, int fd, void *data)
{
    int32_t rc;

    S_OsSelectInd indMsg;
    rc = OS_SelectRecvByFd(fd, &indMsg);
    IF_RETURN(!=, O5G_RC_OK, rc, NO_RETURN_VALUE, "UE_L2_L3I_IndProcess() OS_SelectRecv() error!\n");

    switch (indMsg.ind)
    {
    case UE_L2_INTRA_IND_MSG_L1_RSP_MSG:
        UE_L2_L3I_ProcL1ApiRspMsg();
        break;
    default:
        CSP_LOG_WRN(UE_MD_L2_L3I, "UE_L2_L3I_IndProcess() recv unsupport ind[%#x]\n", indMsg.ind);
        break;
    }
}

void UE_L2_L3I_ProcL3L2ConfigReq(S_UeCommMsgHdr *pCommMsgHdr)
{
    S_UeL2L3MsgConfigRsp configRsp;

    configRsp.commMsgHdr.type = UE_L2_L3_MSG_CONFIG_RSP;
    configRsp.commMsgHdr.size = sizeof(configRsp);
    configRsp.ueIdx = ((S_UeL2L3MsgConfigRsp *)pCommMsgHdr)->ueIdx;
    send(gpUeL2L3IntfContext->l3SockFd, &configRsp, sizeof(configRsp), MSG_DONTWAIT);
}

void UE_L2_L3I_ProcL3L2StartReq(S_UeCommMsgHdr *pCommMsgHdr)
{
    S_UeL2L3MsgStartRsp startRsp;

    startRsp.commMsgHdr.type = UE_L2_L3_MSG_START_RSP;
    startRsp.commMsgHdr.size = sizeof(startRsp);
    startRsp.ueIdx = ((S_UeL2L3MsgConfigRsp *)pCommMsgHdr)->ueIdx;
    send(gpUeL2L3IntfContext->l3SockFd, &startRsp, sizeof(startRsp), MSG_DONTWAIT);
}

void UE_L2_L3I_MsgProcess(int32_t event, int fd, void *data)
{
    int32_t rc;
    S_UeCommMsgHdr *pCommMsgHdr;

    rc = recv(fd, gpUeL2L3IntfContext->sockRecvBuffer, SOCK_BUFFER_SIZE, MSG_DONTWAIT);
    IF_RETURN(>, (int32_t)sizeof(S_UeCommMsgHdr), rc, NO_RETURN_VALUE, "UE_L2_L3I_MsgProcess() recv() error! rc[%d] < %u\n",
        rc, (uint32_t)sizeof(S_UeCommMsgHdr));

    pCommMsgHdr = (S_UeCommMsgHdr *)gpUeL2L3IntfContext->sockRecvBuffer;
    switch (pCommMsgHdr->type)
    {
    case UE_L1_API_MSG_CONFIG_REQ:
        CSP_LOG_INF(UE_MD_L2_L3I, "UE_L2_L3I_MsgProcess() recv UE_L1_API_MSG_CONFIG_REQ\n");
        VRB_PUT(rc, gpUeL2Context->pL3iL1iMsgQue, pCommMsgHdr, pCommMsgHdr->size);
        break;
    case UE_L1_API_MSG_SYNC_REQ:
        CSP_LOG_INF(UE_MD_L2_L3I, "UE_L2_L3I_MsgProcess() recv UE_L1_API_MSG_SYNC_REQ\n");
        VRB_PUT(rc, gpUeL2Context->pL3iL1iMsgQue, pCommMsgHdr, pCommMsgHdr->size);
        break;
    case UE_L3_L2_MSG_CONFIG_REQ:
        CSP_LOG_INF(UE_MD_L2_L3I, "UE_L2_L3I_MsgProcess() recv UE_L3_L2_MSG_CONFIG_REQ\n");
        UE_L2_L3I_ProcL3L2ConfigReq(pCommMsgHdr);
        break;
    case UE_L3_L2_MSG_START_REQ:
        CSP_LOG_INF(UE_MD_L2_L3I, "UE_L2_L3I_MsgProcess() recv UE_L3_L2_MSG_START_REQ\n");
        UE_L2_L3I_ProcL3L2StartReq(pCommMsgHdr);
        break;
    default:
        CSP_LOG_WRN(UE_MD_L2_L3I, "UE_L2_L3I_MsgProcess() recv unsupport msg[%#x]\n", pCommMsgHdr->type);
        break;
    }
}

void UE_L2_L3I_PrdProcess()
{

}

void *UE_L2_L3I_Task(void* arg)
{
    int fd;
    uint64_t lastTimeStamp;

    fd = gpUeL2L3IntfContext->selector.recvFd;
    POLLER_Add(gpUeL2L3IntfContext->poller, fd, UE_L2_L3I_IndProcess, NULL, NULL, NULL);

    fd = gpUeL2L3IntfContext->l3SockFd;
    POLLER_Add(gpUeL2L3IntfContext->poller, fd, UE_L2_L3I_MsgProcess, NULL, NULL, NULL);

    while (1)
    {
        POLLER_Poll(gpUeL2L3IntfContext->poller, 5);

        if (CSP_ArrivalDelayTimeUs(&lastTimeStamp, 10))
        {
            UE_L2_L3I_PrdProcess();
        }
        pthread_testcancel();
    }

    return NULL;
}

int32_t UE_L2_L3I_Start(void)
{
    int32_t rc;

    rc = OS_ThreadCreate(&gpUeL2L3IntfContext->tid, UE_L2_L3I_Task, NULL);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "RAN_L2_L3I_Start() OS_ThreadCreate() error!\n");

    return O5G_RC_OK;
}

int32_t UE_L2_L3I_Stop(void)
{
    int32_t rc;

    rc = OS_ThreadCancel(gpUeL2L3IntfContext->tid);
    IF_RETURN(!=, O5G_RC_OK, rc, O5G_RC_ER, "RAN_L2_L3I_Stop() OS_ThreadCancel() error!\n");

    return O5G_RC_OK;
}

